/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package algorithms;

import structure.DataPoint;
import structure.State;
import structure.Variable;
import utilities.*;

/**
 * This is the algorithm which calculates the unweughted L1 metric of the data set
 * @author Gary Furlong
 */
public class L1Metric {

    /**
     * Static function which calculates the L1 metric between 2 variables
     * @param a The first Variable
     * @param b The Second Variable
     * @return The unweighted L1 metric
     */
    public static double calculate(Variable a, Variable b){
        int numberOfStatesA = a.getNumberOfStates();  //The number of states for variable A
        int numberOfStatesB = b.getNumberOfStates();  //The number of states for variable B
        double divisor = (double)StringParse.data.getNumberOfDataPoints();  //The value of the divisor (equal to the number of DPs)
        double total = 0;  // The current total value of the sum of dependencies
        double[][] cooccurance = new double[numberOfStatesA][numberOfStatesB];  //The current cooccurance matrix
        double[] probA = new double[numberOfStatesA];  //The current discrete probability distribution of A
        double[] probB = new double[numberOfStatesB];  //The current discrete probability distribution of B

        //Iterate through all of the states in variable A
        for(int i=1; i<numberOfStatesA+1; i++){
             //Iterate through all of the states in variable B
            for(int j=1; j<numberOfStatesB+1; j++){
                //Counts the number of times where the two variables with the two states occur
                double and1and2 = compareStates(a,b,a.getStateById(i),b.getStateById(j));
                //Works out the probabilty of the given combination happening
                cooccurance[i-1][j-1] = and1and2/divisor;
                /*System.out.println("Co-occurance matrix:[" + i +"-1][" + j + "-1] = " + cooccurance[i-1][j-1]);*/
            }
        }
        //Iterate through all of the states in variable A
        for(int i=0; i<numberOfStatesA; i++){
            //Iterate through all of the states in variable B
            for(int j=0; j<numberOfStatesB; j++){
               //Works out the probability distribution iteratively wy adding the jth member of the cooccurance array
               probA[i] = probA[i] + cooccurance[i][j];
            }
            //System.out.println("********** -> Prob A:[" + i +"] = " + probA[i]);
        }
        //Iterate through all of the states in variable B
        for(int i=0; i<numberOfStatesB; i++){
            //Iterate through all of the states in variable A
            for(int j=0; j<numberOfStatesA; j++){
               //Works out the probability distribution iteratively wy adding the jth member of the cooccurance array
               probB[i] = probB[i] + cooccurance[j][i];
            }
            //System.out.println("********** -> Prob B:[" + i +"] = " + probB[i]);
        }

        //USED FOR ERROR CHECKING

        
        for (int i = 0; i < numberOfStatesB; i++) {
            for (int j = 0; j < numberOfStatesA; j++) {
                System.out.print(cooccurance[j][i] + " ");
            }
            System.out.print("|" + probB[i] + "\n");
        }
        for (int j = 0; j < numberOfStatesA; j++) {
            System.out.print("-");
        }
        System.out.println();
        for (int j = 0; j < numberOfStatesA; j++) {
            System.out.print(probA[j] + " ");
        }
        

        //Iterate through all of the states in variable A
        for(int i=0; i<numberOfStatesA; i++){
            //Iterate through all of the states in variable B
            for(int j=0; j<numberOfStatesB; j++){
                //Adds the next partial L1 metric to the current total of L1 metrics
                double tempvar = probA[i]*probB[j];
                tempvar = cooccurance[i][j] - tempvar;
                tempvar = Math.abs(tempvar);
                total = total + tempvar;
            }
        }
        /*System.out.println("Total = " + total);*/

        return total;
    }

    /**
     * Counts the number of of times two states in two different variables occur
     * @param a The first variable to be compared
     * @param b The second variable to be compared
     * @param s1 The state to compare (tied to variable a)
     * @param s2 The state to compare (tied to variable b)
     * @return
     */
    public static double compareStates(Variable a, Variable b, State s1, State s2){ //Currently set to private, you can change to public if you need to use it
        int numberOfInstances = 0;

        for (DataPoint d1 : StringParse.data.getDataPoints()){
           // System.out.println("d1:"+d1.getId());
            for (DataPoint d2 : StringParse.data.getDataPoints()){
               // System.out.println("d2:"+d2.getId());
                if((d1.getVariable().getId()==a.getId())
                        &&(d2.getVariable().getId()==b.getId())&&(s1.getStateNumber()==d1.getState().getStateNumber())
                        &&(s2.getStateNumber()==d2.getState().getStateNumber())
                        &&(d1.getId()==d2.getId())
                      ){
                    //System.out.println("(VAR:"+a.getId()+", STATE:"+s1.getStateNumber() +","+ ")(VAR:"+b.getId()+", STATE:"+s2.getStateNumber()+","+")(dp:"+d1.getId()+", dp:"+d2.getId()+")");
                    numberOfInstances = numberOfInstances + 1;
                }
            }
            
        }
        //System.out.println("Instances:"+numberOfInstances);

        return numberOfInstances;
    }
}
